#include "QSPrecompiledHeaders.h"
#include "CEGUI/QSCEGUISystem.h"
#include "Ogre/QSOgreRenderSystem.h"

#include <CEGUI/CEGUI.h>
#include <OgreCEGUIRenderer.h>

using namespace QS;

static CEGUI::Key::Scan keys[256];
static CEGUI::MouseButton buttons[10];

static void initCEGUIKeys()
{	
	//letters
	keys[Key::A] = CEGUI::Key::A;
	keys[Key::B] = CEGUI::Key::B;
	keys[Key::C] = CEGUI::Key::C;
	keys[Key::D] = CEGUI::Key::D;
	keys[Key::E] = CEGUI::Key::E;
	keys[Key::F] = CEGUI::Key::F;
	keys[Key::G] = CEGUI::Key::G;
	keys[Key::H] = CEGUI::Key::H;
	keys[Key::I] = CEGUI::Key::I;
	keys[Key::J] = CEGUI::Key::J;
	keys[Key::K] = CEGUI::Key::K;
	keys[Key::L] = CEGUI::Key::L;
	keys[Key::M] = CEGUI::Key::M;
	keys[Key::N] = CEGUI::Key::N;
	keys[Key::O] = CEGUI::Key::O;
	keys[Key::P] = CEGUI::Key::P;
	keys[Key::Q] = CEGUI::Key::Q;
	keys[Key::R] = CEGUI::Key::R;
	keys[Key::S] = CEGUI::Key::S;
	keys[Key::T] = CEGUI::Key::T;
	keys[Key::U] = CEGUI::Key::U;
	keys[Key::V] = CEGUI::Key::V;
	keys[Key::W] = CEGUI::Key::W;
	keys[Key::X] = CEGUI::Key::X;
	keys[Key::Y] = CEGUI::Key::Y;
	keys[Key::Z] = CEGUI::Key::Z;

	//numbers
	keys[Key::Num0] = CEGUI::Key::Zero;
	keys[Key::Num1] = CEGUI::Key::One;
	keys[Key::Num2] = CEGUI::Key::Two;
	keys[Key::Num3] = CEGUI::Key::Three;
	keys[Key::Num4] = CEGUI::Key::Four;
	keys[Key::Num5] = CEGUI::Key::Five;
	keys[Key::Num6] = CEGUI::Key::Six;
	keys[Key::Num7] = CEGUI::Key::Seven;
	keys[Key::Num8] = CEGUI::Key::Eight;
	keys[Key::Num9] = CEGUI::Key::Nine;

	//punctuation
	keys[Key::Comma]		= CEGUI::Key::Comma;
	keys[Key::Equals]		= CEGUI::Key::Equals;
	keys[Key::Minus]		= CEGUI::Key::Minus;
	keys[Key::Period]		= CEGUI::Key::Period;
	keys[Key::Semicolon]	= CEGUI::Key::Semicolon;
	keys[Key::Apostrophe]	= CEGUI::Key::Apostrophe;
	keys[Key::LeftBracket]	= CEGUI::Key::LeftBracket;
	keys[Key::RightBracket]	= CEGUI::Key::RightBracket;

	//navigation
	keys[Key::UpArrow]		= CEGUI::Key::ArrowUp;
	keys[Key::DownArrow]	= CEGUI::Key::ArrowDown;
	keys[Key::LeftArrow]	= CEGUI::Key::ArrowLeft;
	keys[Key::RightArrow]	= CEGUI::Key::ArrowRight;
	keys[Key::Insert]		= CEGUI::Key::Insert;
	keys[Key::Home]			= CEGUI::Key::Home;
	keys[Key::End]			= CEGUI::Key::End;
	keys[Key::PageUp]		= CEGUI::Key::PageUp;
	keys[Key::PageDown]		= CEGUI::Key::PageDown;

	//function keys
	keys[Key::F1]	= CEGUI::Key::F1;
	keys[Key::F2]	= CEGUI::Key::F2;
	keys[Key::F3]	= CEGUI::Key::F3;
	keys[Key::F4]	= CEGUI::Key::F4;
	keys[Key::F5]	= CEGUI::Key::F5;
	keys[Key::F6]	= CEGUI::Key::F6;
	keys[Key::F7]	= CEGUI::Key::F7;
	keys[Key::F8]	= CEGUI::Key::F8;
	keys[Key::F9]	= CEGUI::Key::F9;
	keys[Key::F10]	= CEGUI::Key::F10;
	keys[Key::F11]	= CEGUI::Key::F11;
	keys[Key::F12]	= CEGUI::Key::F12;

	//editing
	keys[Key::Enter]		= CEGUI::Key::Return;
	keys[Key::Backspace]	= CEGUI::Key::Backspace;
	keys[Key::Delete]		= CEGUI::Key::Delete;
	keys[Key::Space]		= CEGUI::Key::Space;

	//meta
	keys[Key::Shift]	= CEGUI::Key::LeftShift;
	keys[Key::Control]	= CEGUI::Key::LeftControl;

	//mouse buttons
	buttons[Button::Mouse1] = CEGUI::LeftButton;
	buttons[Button::Mouse2] = CEGUI::RightButton;
	buttons[Button::Mouse3] = CEGUI::MiddleButton;
}

	
//
//Hard-coded debug console behavior.  
//TODO: have the client game logic create the debug console
//

bool CEGUISystem::keyDown(const CEGUI::EventArgs& a)
{
	const CEGUI::KeyEventArgs& args = (const CEGUI::KeyEventArgs&)a;
	if (args.scancode == CEGUI::Key::Return)
		return submitButtonClicked(CEGUI::EventArgs());

	return false;
}

bool CEGUISystem::submitButtonClicked(const CEGUI::EventArgs&)
{			
	const CEGUI::String& input = mTextBox->getText();
	mHistory->setText(mHistory->getText() + "] " + input);
	mEngine->getGameSystem()->executeCommand(input.c_str());

	mTextBox->setText("");			

	return true;
}


CEGUISystem::~CEGUISystem()
{

}

void CEGUISystem::initialize()
{
	OgreRenderSystem* sys = dynamic_cast<OgreRenderSystem*>(mEngine->getRenderSystem());
	assert(sys && "Invalid render host");

	Ogre::RenderWindow* window = sys->getOgreRenderWindow();
	Ogre::SceneManager* sceneManager = sys->getOgreSceneManager();
	Ogre::ResourceGroupManager& groupManager = Ogre::ResourceGroupManager::getSingleton();
	initCEGUIKeys();
	mEngine->getEventSystem()->addEventListener(this);

	//Add gui data dir
	groupManager.addResourceLocation("data/gui/resources", "FileSystem", "GUI");
	
	//create OGRE renderer
	CEGUI::OgreCEGUIRenderer* guiRenderer = new CEGUI::OgreCEGUIRenderer(
		window,
		Ogre::RENDER_QUEUE_OVERLAY,
		false, 
		3000, 
		sceneManager);		

	//create CEGUI gui system
	CEGUI::System* system = new CEGUI::System(guiRenderer);	

	//initialize basic resources
	CEGUI::SchemeManager::getSingleton().loadScheme("VanillaSkin.scheme");
	system->setDefaultMouseCursor("Vanilla-Images", "MouseArrow");
	
	//create the debug console
#ifndef NDEBUG
	CEGUI::Window* console= CEGUI::WindowManager::getSingleton().loadWindowLayout("console.layout");
	system->setGUISheet(console);

	mSubmit = (CEGUI::PushButton*)console->getChild("Console/Submit");
	mTextBox = (CEGUI::Editbox*)console->getChild("Console/Editbox");			
	mHistory = (CEGUI::MultiLineEditbox*)console->getChild("Console/History");
	
	mSubmit->subscribeEvent(CEGUI::PushButton::EventClicked, CEGUI::Event::Subscriber(&CEGUISystem::submitButtonClicked, this));
	mTextBox->subscribeEvent(CEGUI::Window::EventKeyDown, CEGUI::Event::Subscriber(&CEGUISystem::keyDown, this));


#endif
}

void CEGUISystem::shutdown()
{
	//TODO: not sure what else needs to be done to fully shutdown CEGUI
	CEGUI::WindowManager::getSingleton().destroyAllWindows();

	mEngine->getEventSystem()->removeEventListener(this);
}

void CEGUISystem::update()
{
	//nothing to do.  CEGUI updates when OGRE updates
}

void CEGUISystem::printToConsole(const String& text)
{
#ifndef NDEBUG
	mHistory->setText(mHistory->getText() + text);
	mHistory->setCaratIndex(mHistory->getText().size());
	mHistory->ensureCaratIsVisible();
#endif
}

void CEGUISystem::processEvent(const Event& e)
{
	CEGUI::System& sys = CEGUI::System::getSingleton();
	const KeyEventArgs* keyArgs = static_cast<const KeyEventArgs*>(e.getArgs());
	const MouseEventArgs* mouseArgs = static_cast<const MouseEventArgs*>(e.getArgs());

	switch (e.getTypeId())
	{
	case EventType::KeyDown:
		sys.injectKeyDown(keys[keyArgs->key]);
		sys.injectChar(keyArgs->character);
		break;
	case EventType::KeyUp:
		sys.injectKeyUp(keys[keyArgs->key]);
		break;
	case EventType::MouseDown:
		sys.injectMouseButtonDown(buttons[mouseArgs->button]);
		break;
	case EventType::MouseUp:
		sys.injectMouseButtonUp(buttons[mouseArgs->button]);
		break;
	case EventType::MouseMove:
		sys.injectMouseMove(mouseArgs->dx, mouseArgs->dy);
		break;	
	}
}